package com.qire.manhua.view.comicReader.renderer;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class PicturePoolExecutor extends ThreadPoolExecutor {

    // 核心线程和最大线程都是cpu核心数 + 1
    private static final int MAX_CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() + 1;
    // 保持生存时间，存活30秒回收线程
    private static final long KEEP_ALIVE_TIME = 30L;
    // 保持活着的时间单位,秒
    private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;

    /** 线程工厂 */
    private static class PoolThreadFactory implements ThreadFactory {
        private final String namePrefix;
        private final AtomicInteger nextId = new AtomicInteger(1);
        // 定义线程组名称，在 jstack 命令 问题排查时，非常有帮助
        PoolThreadFactory(String whatGroupName) {
            namePrefix = String.format("来自资源工厂的：%s -工作线程-", whatGroupName);
        }

        @Override
        public Thread newThread(Runnable task) {
            String name = namePrefix + nextId.getAndIncrement();
            Thread thread = new Thread(null, task, name, 0);
            System.out.println(thread.getName());
            return thread;
        }
    }

    public PicturePoolExecutor() {
        super(MAX_CORE_POOL_SIZE, MAX_CORE_POOL_SIZE,
                KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT,
                new ArrayBlockingQueue<>(64),
                new PoolThreadFactory("ComicPictureDown"),
                // 滑动阅读的场景是，新追加的才是用户当前看到的，那么新追加的才是最希望马上处理的，但是如果直接开辟线程则可能由于不停滑动导致线程在某一时刻开辟过多。
                // 所以最优方案应该是，移除排队队列里最老的项目，然后头插进排队队列中，以便在线程池有空闲资源是第一时间获得资源下载。这需要重写策略以及排队队列容器。
                // 所以避免写过多代码麻烦，采用了默认丢弃最早的资源下载，然后尾插如等待队列。如果后期有下载秒开的需求，可以按照上面的逻辑来额外实现优化。
                new DiscardOldestPolicy());

        //核心线程也会被销毁
        allowCoreThreadTimeOut(true);
    }

    /**
     * 任务是否存在于等待队列中
     * @param pictureLoadTask 目标任务
     * @return true 表示存在， false表示不存在
     */
    public boolean existInWaitQueue(Runnable pictureLoadTask) {
        return getQueue().contains(pictureLoadTask);
    }

    /**
     * 取消正在等待执行中的任务
     * @param taskTag 任务标记
     * @return 如果存在并删除了返回 true，否则false
     */
    public boolean cancelTask(Object taskTag) {
        return getQueue().remove(taskTag);
    }

}
